// Created by Windward Studios - no copyright is claimed. This code can be used in
// any manner by anyone for any reason. There is no copyright of any kind on it. You may
// use it in commercial products. You may change it without sharing those changes.
// We ask that you keep the "created by Windward Studios" in a comment at the top.

using System;
using System.Data;
using Kailua.net.windward.utils;

namespace net.windward.utils.ado
{
	/// <summary>
	/// A column in a table or view.
	/// </summary>
	public class WrColumn : WrDbElement
	{
		protected readonly DbType dbType;
		private readonly string primaryKey;

		/// <summary>
		/// Create a column element.
		/// </summary>
		/// <param name="name">The name of the column.</param>
		/// <param name="dbType">The type of this column.</param>
		public WrColumn(string name, DbType dbType)
			: base(null, name, null)
		{
			this.dbType = dbType;
			primaryKey = null;
		}

		/// <summary>
		/// Create a column element.
		/// </summary>
		/// <param name="name">The name of the column.</param>
		/// <param name="description">The description (metadata) of the column.</param>
		/// <param name="dbType">The type of this column.</param>
		public WrColumn(string name, string description, DbType dbType)
			: base(null, name, description)
		{
			this.dbType = dbType;
			primaryKey = null;
		}

		/// <summary>
		/// Create a column element.
		/// </summary>
		/// <param name="name">The name of the column.</param>
		/// <param name="description">The description (metadata) of the column.</param>
		/// <param name="dbType">The type of this column.</param>
		/// <param name="primaryKey">The table.column of the primary key this foreign key matches.</param>
		public WrColumn(string name, string description, DbType dbType, string primaryKey)
			: base(null, name, description)
		{
			this.dbType = dbType;
			this.primaryKey = primaryKey;
		}

		/// <summary>
		/// Copy constructor
		/// </summary>
		/// <param name="src">Source object.</param>
		public WrColumn(WrColumn src) : base(src)
		{
			dbType = src.dbType;
			primaryKey = src.primaryKey;
		}

		/// <summary>
		/// The type for this column.
		/// </summary>
		public DbType DbType
		{
			get { return dbType; }
		}

		/// <summary>
		/// Returns true if this column is a datetime type. In this case values it is compared to must be
		/// handled as dates and before/after tests can be made.
		/// </summary>
		public bool IsDateType
		{
			get
			{
				switch (dbType)
				{
					case DbType.Date:
					case DbType.DateTime:
					case DbType.DateTime2:
					case DbType.Time:
						return true;
				}
				return false;
			}
		}

		/// <summary>
		/// Returns true if this column is a numeric type. In this case values it is compared to should not be
		/// quoted and inequality tests can be made.
		/// </summary>
		public bool IsNumericType
		{
			get
			{
				switch (dbType)
				{
					case DbType.Byte:
					case DbType.Currency:
					case DbType.Decimal:
					case DbType.Double:
					case DbType.Int16:
					case DbType.Int32:
					case DbType.Int64:
					case DbType.SByte:
					case DbType.Single:
					case DbType.UInt16:
					case DbType.UInt32:
					case DbType.UInt64:
					case DbType.VarNumeric:
						return true;
				}
				return false;
			}
		}

		/// <summary>
		/// Returns true if this column is a string type. In this case values it is compared to must be
		/// quoted and like tests can be made.
		/// </summary>
		public bool IsStringType
		{
			get
			{
				switch (dbType)
				{
					case DbType.AnsiString:
					case DbType.AnsiStringFixedLength:
					case DbType.String:
					case DbType.StringFixedLength:
						return true;
				}
				return false;
			}
		}

		/// <summary>
		/// If this is the foreign key in a PK:FK relationship this string is the table.column of the matching
		/// primary key. This value is null if it is not a foreign key.
		/// </summary>
		public string PrimaryKey
		{
			get { return primaryKey; }
		}

		#region type conversion utilities


		private static readonly string[,] DBTypeConversionKey = new string[,]
		                                                        	{
		                                                        		{"BigInt", "System.Int64"},
		                                                        		{"Binary", "System.Byte[]"},
		                                                        		{"Bit", "System.Boolean"},
		                                                        		{"Char", "System.String"},
		                                                        		{"DateTime", "System.DateTime"},
		                                                        		{"Decimal", "System.Decimal"},
		                                                        		{"Float", "System.Double"},
		                                                        		{"Image", "System.Byte[]"},
		                                                        		{"Int", "System.Int32"},
		                                                        		{"Money", "System.Decimal"},
		                                                        		{"NChar", "System.String"},
		                                                        		{"NText", "System.String"},
		                                                        		{"NVarChar", "System.String"},
		                                                        		{"Real", "System.Single"},
		                                                        		{"SmallDateTime", "System.DateTime"},
		                                                        		{"SmallInt", "System.Int16"},
		                                                        		{"SmallMoney", "System.Decimal"},
		                                                        		{"Text", "System.String"},
		                                                        		{"Timestamp", "System.DateTime"},
		                                                        		{"TinyInt", "System.Byte"},
		                                                        		{"UniqueIdentifer", "System.Guid"},
		                                                        		{"VarBinary", "System.Byte[]"},
		                                                        		{"VarChar", "System.String"},
		                                                        		{"Variant", "System.Object"}
		                                                        	};

		///<summary>
		/// Convert from a system type to a DbType.
		///</summary>
		///<param name="sourceType">The system Type.</param>
		///<returns>The equivilent DbType.</returns>
		public static DbType SystemTypeToDbType(Type sourceType)
		{

			DbType dbt;
			try
			{
				dbt = (DbType)Enum.Parse(typeof(DbType), sourceType.Name);
			}
			catch
			{
				Trap.trap();
				dbt = DbType.Object;
			}
			return dbt;
		}

		/// <summary>
		/// Convert from a DbType to a system Type.
		/// </summary>
		/// <param name="sourceType">The DbType.</param>
		/// <returns>The equivilent system Type.</returns>
		public static Type DbTypeToSystemType(SqlDbType sourceType)
		{
			string SystemType = string.Empty;
			string DBType = sourceType.ToString();
			int keyCount = DBTypeConversionKey.GetLength(0);

			for (int i = 0; i < keyCount; i++)
				if (DBTypeConversionKey[i, 0].Equals(DBType)) 
					SystemType = DBTypeConversionKey[i, 1];

			if (SystemType == string.Empty) SystemType = "System.Object";

			return Type.GetType(SystemType);
		}

		#endregion
	}
}
